<?php

namespace libs;

class Autoloader {

    protected static $_instance = null;
    protected static $_namespaces = array();

    protected function __construct() {
        
    }

    public static function getInstance() {
        if (self::$_instance === null)
            self::$_instance = new self();

        return self::$_instance;
    }

    public static function addNamespace($namespaceName, $namespacePath, $forceReplace = false) {
        if (!is_string($namespaceName))
            throw new \Exception('Namespace name parameter must be a string');
        if (!is_dir($namespacePath))
            throw new \Exception('Namespace path must be a valid directory');

        if (array_key_exists($namespaceName, self::$_namespaces) && !$forceReplace)
            throw new \Exception('Namespace directory "' . $namespacePath . '" already registered');

        self::$_namespaces[$namespaceName] = realpath($namespacePath) . DIRECTORY_SEPARATOR;
    }

    public function register() {
        if (!function_exists('spl_autoload_register'))
            throw new \Exception('spl_autoload does not exist in this PHP installation');
        spl_autoload_register(array($this, '_autoload'));
    }

    protected function _autoload($class) {
        $namespace = self::_getRootNamespace($class);
        if ($namespace !== null && array_key_exists($namespace, self::$_namespaces)) {
            $classPath = str_replace(array($namespace . '\\', '\\'), array(self::$_namespaces[$namespace], DIRECTORY_SEPARATOR), $class);
            $this->_includeClass($classPath, $class);
        } else
            throw new \Exception('Class : "' . $class . '" not found');
    }

    protected function _getRootNamespace($class) {
        $rootNamespaceLenght = 0;
        if (strpos($class, '\\'))
            $rootNamespaceLenght = strcspn($class, '\\');

        if ($rootNamespaceLenght == 0)
            return null;
        return substr($class, 0, $rootNamespaceLenght);
    }

    protected function _includeClass($classPath, $className) {
        if (file_exists($classPath . '.class.php')) {
            require_once($classPath . '.class.php');
            if (class_exists($className, false) || interface_exists($className, false))
                return;
        }

        if (file_exists($classPath . '.abstract.php')) {
            require_once($classPath . '.abstract.php');
            if (class_exists($className, false) || interface_exists($className, false))
                return;
        }

        if (file_exists($classPath . '.interface.php')) {
            require_once($classPath . '.interface.php');
            if (class_exists($className, false) || interface_exists($className, false))
                return;
        }

        if (file_exists($classPath . '.php')) {
            require_once($classPath . '.php');
            if (class_exists($className, false) || interface_exists($className, false))
                return;
        }
    }

}

?>
